using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Resources;
using System.Windows.Threading;
using MouseExtender.Controls.UserControls;
using MouseExtender.Logic;
using MouseExtender.Logic.Common;
using MouseExtender.Logic.Entities;
using MouseExtender.Logic.Enums;
using MouseExtender.Logic.Events;
using MouseExtender.Logic.Helpers;
using MouseExtender.Logic.Managers;
using MouseExtender.Logic.ShellLink;
using MouseExtender.Resources;


#if SNOOP
using System.Windows.Media;
#endif
namespace MouseExtender
{
    public partial class MainWindow : Window
    {
        #region Constants

        private const double farAwayLeft = -2000;

        #endregion

        #region Fields

        private WindowsHook _globalHook = null;
        private bool _isGlobalHookSet = false;
        private PopupUC _popup = null;
        private SessionNotificationUtil _sessionNotificationUtility = null;
        private bool? _isStarting = null;
        private bool _isContentRendered = false;
        private Dispatcher _backgroundDispatcher = null;
        private bool _activationStarted = false;
        private GlobalKeyboardHotkeys _hotkeys = null;
        #endregion

        #region Properties

        private UserSettings Settings
        {
            get
            {
                return SettingsManager.CurrentSettings;
            }
        }

        internal bool? IsStarting
        {
            get
            {
                return _isStarting;
            }
            set
            {
                if (value == true)
                {
                    Opacity = 0;
                }
                else
                {
                    Opacity = 1;
                }
                _isStarting = value;
            }
        }

        public bool IsOpenPopup
        {
            get
            {
                return _popup.IsOpen;
            }
            set
            {
                _popup.IsOpen = value;
                SetLauncherDisabled(_popup.IsOpen);
            }
        }

        #endregion

        #region Constructors

        public MainWindow()
        {
            InitializeComponent();
            App.UIContext = this.Dispatcher;
            //tabs notify launcher that current changed
            //ucTabs.CurrentTabChanged += ucLauncher.ucTabs_CurrentTabChanged;
            Focus();
        }

        #endregion

        #region Methods

        private void ShowWindow(bool stealFocus)
        {
            if (!stealFocus)
            {
                Topmost = !PopupUC.IsAnyPopupOpen;
                base.Show();
                Activate();
            }
            else
            {
                CheatFormActivation();
            }
        }

        /// <summary>
        /// Shows window.
        /// </summary>
        public void ShowWindow()
        {
            ShowWindow(false);
        }

        private void HideWindow(bool checkPopupAndSetting)
        {
            if (checkPopupAndSetting)
            {
                if (PopupUC.IsAnyPopupOpen || Settings.DontHidePanel)
                    return;
            }

            base.Hide();
            Topmost = false;
        }

        /// <summary>
        /// Hides window
        /// </summary>
        public void HideWindow()
        {
            HideWindow(true);
        }

        /// <summary>
        /// Shows window at specified position.
        /// </summary>
        /// <param name="point">Point at which window would be shown.</param>
        public void ShowInPoint(Point point)
        {
            if (Settings.HideOnMiddleClickWhenOpened && (Visibility == Visibility.Visible))
            {
                HideWindow(false);
            }
            else
            {
                if (!PopupUC.IsAnyPopupOpen)
                {
                    Top = point.Y - grid.ActualHeight / 2 - 10;
                    Left = point.X - grid.ActualWidth / 2 - 14;

                    //TODO: fix height taking into account additional monitor position (relatively to primary one
                    //also virtual height returned of primary monitor, not actual pressed

                    //for multimonitor support remove positional normalization.
                    //X/Y is negative for another monitor if it from left/top side of primary

                    this.CheatFormActivation();
                }
            }
        }

        public void NormalizeLauncherItemNumbers()
        {
            Settings.LauncherItems.Sort((a, b) => a.ItemNumber.CompareTo(b.ItemNumber));
            for (int i = 0; i < Settings.LauncherItems.Count; i++)
            {
                Settings.LauncherItems[i].ItemNumber = i;
            }
        }

        public void ShowHideCloseButton()
        {
            if (Settings.HideCloseButton)
            {
                btnClose.Visibility = Visibility.Collapsed;
                btnMinimize.Margin = new Thickness(0, 0, 4, 0);
            }
            else
            {
                btnClose.Visibility = Visibility.Visible;
                btnMinimize.Margin = new Thickness(0);
            }
        }

        /// <summary>
        /// Sets taskbar icon.
        /// </summary>
        /// <param name="path">Resourse uri for icon image.</param>
        public void SetTaskbarIcon(string path)
        {
            StreamResourceInfo iconStreamInfo = ResourcesHelper.GetStreamInfo(path);
            if (iconStreamInfo == null)
                throw new ApplicationException(string.Format("Couln't find the icon stream specified by the following path: [{0}]", path));

            tbIcon.Icon = new System.Drawing.Icon(iconStreamInfo.Stream);
        }

        /// <summary>
        /// Close Popup and activate Launcher.
        /// </summary>
        private void CancelPopup()
        {
            if (_popup != null)
                _popup.IsOpen = false;

            SetLauncherDisabled(false);
        }

        /// <summary>
        /// Creates new Popup and adds it visual tree.
        /// </summary>
        private void CreatePopup()
        {
            if (_popup == null)
            {
                _popup = new PopupUC();
                grid.Children.Add(_popup);
            }
        }

        /// <summary>
        /// Initialing common logic and icons
        /// </summary>
        private void AdjustMouseExtender()
        {
            //Initialize logger
            Logger.CriticalErrorOccurred += new EventHandler(CriticalErrorOccurred);
            InitializeSettings();
            //Setup system tray icon and context menu
            ucSystemButtonsBar.Visibility = Settings.ShowSystemButtonsBar == true ? Visibility.Visible : Visibility.Collapsed;

            ThreadPool.QueueUserWorkItem(s =>
            {
                InternetAccessManager.Initialize();
                Dispatcher.BeginInvoke(new Action(() =>
                {
                    UpdateManager.CheckUpdatesPeriodicaly(this, EventArgs.Empty);
                }));
            });
        }

        /// <summary>
        /// Initialization of settings stored in cfg-file
        /// </summary>
        private void InitializeSettings()
        {
            //Load settings
            NormalizeLauncherItemNumbers();
            UpdateManager.UpdateStatusChanged += UpdateStatusChanged;
            if (SingleInstanceManager.IsUpdated)
            {
                UpdateManager.Updated();
            }
        }

        /// <summary>
        /// Show ballon with updates notification near taskbar icon.
        /// </summary>
        private void ShowUpdatesNotification()
        {
            //show popup
            UpdateCheckBalloonUC balloon = new UpdateCheckBalloonUC()
            {
                DataContext = UpdateManager.UpdatesInfo,
            };
            tbIcon.ShowCustomBalloon(balloon, PopupAnimation.Slide, 7000);
        }

        /// <summary>
        /// Setting correct styles thus window is not visible in alt-tab
        /// </summary>
        private void SetCorrectWindowStyle()
        {
            WindowInteropHelper helper = new WindowInteropHelper(this);
            int exStyle = (int)Win32Helper.GetWindowLong(helper.Handle, (int)WindowStylesHelper.GetWindowLongFields.GWL_EXSTYLE);
            exStyle |= (int)WindowStylesHelper.ExtendedWindowStyles.WS_EX_TOOLWINDOW;
            WindowStylesHelper.SetWindowLong(helper.Handle, (int)WindowStylesHelper.GetWindowLongFields.GWL_EXSTYLE, (IntPtr)exStyle);
        }

        /// <summary>
        /// Disables or enables Launcher.
        /// </summary>
        /// <param name="setDisabled"></param>
        private void SetLauncherDisabled(bool setDisabled)
        {
            SetGlobalHook(!setDisabled);
            IsHitTestVisible = !setDisabled;
            ucLauncher.Opacity = ucSystemButtonsBar.Opacity = setDisabled ? 0.5 : 1.0;
            ContextMenu.Visibility = setDisabled ? Visibility.Collapsed : Visibility.Visible;
            ContextMenu.IsEnabled = !setDisabled;
            ContextMenuService.SetIsEnabled(this, !setDisabled);
        }

        /// <summary>
        /// Set mouse button global hook
        /// </summary>
        public void SetGlobalHook(bool start)
        {
            _backgroundDispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
                    {
                        if (start && !_isGlobalHookSet)
                        {
                            _globalHook = new WindowsHook(Settings.MouseKeysCombination);
                            _globalHook.MouseHookEvent += new MouseHookHandler(MouseButtonGlobalClick);
                            _globalHook.PreviewMouseHookEvent += new EventHandler<PreviewMouseHookCancelArgs>(PreviewMouseHookEvent);
                            _globalHook.MouseWheelEvent += new MouseHookHandler(MouseGlobalWheel);
                            _globalHook.PreviewMouseWheelHookEvent += new EventHandler<PreviewMouseHookCancelArgs>(PreviewMouseWheelHookEvent);

                            _isGlobalHookSet = true;
                        }
                        else if (_globalHook != null && !start && _isGlobalHookSet)
                        {
                            _globalHook.MouseHookEvent -= new MouseHookHandler(MouseButtonGlobalClick);
                            _globalHook.PreviewMouseHookEvent -= new EventHandler<PreviewMouseHookCancelArgs>(PreviewMouseHookEvent);
                            _globalHook.MouseWheelEvent -= new MouseHookHandler(MouseGlobalWheel);
                            _globalHook.PreviewMouseWheelHookEvent -= new EventHandler<PreviewMouseHookCancelArgs>(PreviewMouseWheelHookEvent);
                            _globalHook.Stop();
                            _isGlobalHookSet = false;
                        }
                        SetKeyboardHook(start);
                    }));
        }

        private void SetKeyboardHook(bool start)
        {
            Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
            {
                if (_hotkeys != null)
                {
                    //runs on UI thread already
                    if (start)
                    {
                        if (Settings.Key != System.Windows.Forms.Keys.None)
                        {
                            _hotkeys.RegisterGlobalHotKey((int)Settings.Key, (int)Settings.Modifier);
                        }
                    }
                    else
                    {
                        _hotkeys.UnregisterGlobalHotKey();
                    }
                }
            }));
        }

        /// <summary>
        /// Exits from application.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Exit(object sender, EventArgs e)
        {
            HideWindow();
            Close();
        }

        /// <summary>
        /// Changes label of Enable/Disable menu items
        /// </summary>
        public void SetEnableDisableMenuItem(bool updateOnlyActiveTab = true)
        {
            string headerText = !Settings.IsDisable ? UIResources.Command_Disable : UIResources.Command_Enable;
            miDisable.Header = headerText;
            //TODO: in some cases TaskbarIcon failed to create menu and item is null. TaskbarIcon should be updated or replaced with working one. 
            //May be it is related to case when taskbaricon throws an error dduring creation
            if (miDisableTray != null)
            {
                miDisableTray.Header = headerText;
            }
            ucTabs.miDisable.Header = headerText;
            if (updateOnlyActiveTab)
            {
                if (ucLauncher.ActivePanel != null)
                {
                    if (ucLauncher.ActivePanel.ChildrenContainer != null)
                    {
                        foreach (LauncherItemUC launcherItem in ucLauncher.ActivePanel.ChildrenContainer)
                        {
                            launcherItem.miDisable.Header = headerText;
                        }
                    }
                }
            }
            else
            {
                //drop item cache and refresh current tab
                ucLauncher.Refresh(true, null);
            }
        }

        private void StartBackgroundUIThread()
        {
            Thread backgroundThread = new Thread(() =>
            {
                _backgroundDispatcher = Dispatcher.CurrentDispatcher;
                _backgroundDispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => SetGlobalHook(true)));
                Dispatcher.Run();
            });
            backgroundThread.IsBackground = true;
            backgroundThread.SetApartmentState(ApartmentState.STA);
            backgroundThread.Start();
        }

        private bool? CheatFormActivation()
        {
            bool? setfore = null;

            this.Topmost = true;

            IntPtr currentForegroundWindow = Win32Helper.GetForegroundWindow();
            IntPtr thisWindowHandle = new WindowInteropHelper(this).Handle;
            uint thisWindowThreadId = Win32Helper.GetWindowThreadProcessId(thisWindowHandle, IntPtr.Zero);
            uint currentForegroundWindowThreadId = Win32Helper.GetWindowThreadProcessId(currentForegroundWindow, IntPtr.Zero);
            Win32Helper.AttachThreadInput(currentForegroundWindowThreadId, thisWindowThreadId, true);

            setfore = Win32Helper.SetForegroundWindow(thisWindowHandle);

            Win32Helper.AttachThreadInput(currentForegroundWindowThreadId, thisWindowThreadId, false);

            this.Show();
            setfore = this.Activate();
            this.Focus();


            return setfore;
        }

        #endregion

        #region Events Handlers

        //This is the earliest time when window handle is available
        protected override void OnSourceInitialized(EventArgs e)
        {
            base.OnSourceInitialized(e);
            Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
            {
                _hotkeys = new GlobalKeyboardHotkeys(this);
            }));
            StartBackgroundUIThread();
        }

        private void CriticalErrorOccurred(object sender, EventArgs e)
        {
            Logger logger = sender as Logger;
            if (logger != null)
            {
                string message = String.Format(Constants.Messages.ErrorMessage, logger.LastEventId);
                if (logger.CriticalErrorException.Message.Contains(Constants.GraphicsCOMExceptionId))
                {
                    message = string.Format("{0}\r\n{1}", message, Constants.Messages.GraphicsCOMException);
                }

                ErrorWindow ew = new ErrorWindow(message, null);
                ew.ShowDialog();
                Close();
            }
        }

        private void Grid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (!PopupUC.IsAnyPopupOpen)
                DragMove();
        }

        /// <summary>
        /// Handles a CheckForUpdatesCompleted event.
        /// </summary>
        private void UpdateStatusChanged(UpdateManager.UpdateInfo info)
        {
            if (info.Error == null)
            {
                switch (info.Status)
                {
                    case UpdateManager.UpdateStatus.None:
                        break;
                    case UpdateManager.UpdateStatus.NoUpdatesAvailable:
                        UpdateManager.UpdatesInfo.Title = Constants.Messages.HaveLatestVersionTitle;
                        UpdateManager.UpdatesInfo.Content = Constants.Messages.HaveLatestVersion;
                        break;
                    case UpdateManager.UpdateStatus.NewVersionAvailable:
                        SetTaskbarIcon(Constants.ResourcesUri.MouseExtenderUpdateIcon);
                        UpdateManager.UpdatesInfo.Title = Constants.Messages.NewVersionTitle;
                        UpdateManager.UpdatesInfo.Content = String.Format(Constants.Messages.NewVersionNotification, info.LatestVersion);
                        break;
                    case UpdateManager.UpdateStatus.UpdatesDownloaded:
                        UpdateManager.UpdatesInfo.Title = Constants.Messages.ReadyToInstallTitle;
                        UpdateManager.UpdatesInfo.Content = String.Format(Constants.Messages.ReadyToInstall, info.LatestVersion);
                        break;
                    case UpdateManager.UpdateStatus.UpdateComleted:
                        UpdateManager.UpdatesInfo.Title = Constants.Messages.UpdatesInstalledTitle;
                        UpdateManager.UpdatesInfo.Content = String.Format(Constants.Messages.UpdatesInstalled, info.LatestVersion);
                        break;
                    default:
                        break;
                }
            }
            else
            {
                UpdateManager.UpdatesInfo.Title = String.Empty;
                UpdateManager.UpdatesInfo.Content = String.Format(Constants.Messages.ErrorCheckUpdates, info.Error.Message);
                SetTaskbarIcon(Constants.ResourcesUri.MouseExtenderIcon);
            }

            ShowUpdatesNotification();
        }

        /// <summary>
        /// Handles Selection of Running Program.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void RunningProgramSelected(object sender, LaunchItemSelectedEventArgs e)
        {
            LauncherItem item = e.LauncherItem;
            item.ItemNumber = Settings.LauncherItems.Count;
            item.TabId = ucTabs.CurrentTab;

            if (!e.LauncherItem.IsUrl)
            {
                e.LauncherItem.LaunchPath = PathHelper.RelativeToAppBaseFolderPath(e.LauncherItem.LaunchPath);
                e.LauncherItem.WorkingDirectory = PathHelper.RelativeToAppBaseFolderPath(e.LauncherItem.WorkingDirectory);
            }

            Settings.LauncherItems.Add(e.LauncherItem);
            Settings.SettingChanged();
            ucLauncher.Refresh();
            if (e.IsMultipleSelect)
            {
                //allow adding more than 1 program at time
                return;
            }
            _popup.IsOpen = false;
            SetLauncherDisabled(false);
        }

        /// <summary>
        /// Handles Mouse button Global Hook event.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MouseButtonGlobalClick(object sender, MouseHookEventArgs e)
        {
            App.UIContext.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
                {
                    if (!Settings.IsDisable)
                    {
                        //workaround for context menu instead of previus shield.
                        if ((Settings.MouseKeysCombination & MouseExtenderButton.RightButton) == MouseExtenderButton.RightButton)
                        {
                            _activationStarted = true;
                        }
                        //
                        ShowInPoint(e.CursorPosition);
                    }
                }));
        }

        /// <summary>
        /// Handles Mouse button Global Wheel event.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MouseGlobalWheel(object sender, MouseHookEventArgs e)
        {
            App.UIContext.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
                    {
                        //prevent scroll during items dragging
                        if (IsActive && !ucLauncher.DragIsActive)
                        {
                            List<TabInfo> tabInfoList = SettingsManager.CurrentSettings.TabInfoList;
                            int deltaSign = -Math.Sign(e.MouseDelta);
                            if (tabInfoList.Count > 0)
                            {
                                for (int i = 0; i < tabInfoList.Count; i++)
                                {
                                    TabInfo tabInfo = tabInfoList[i];
                                    if (tabInfo.Id == ucTabs.CurrentTab)
                                    {
                                        int nextTabIndex = ucTabs.CurrentTab;
                                        if (i + deltaSign < 0)
                                            nextTabIndex = tabInfoList.Last().Id;
                                        else if (i + deltaSign >= tabInfoList.Count)
                                            nextTabIndex = tabInfoList.First().Id;
                                        else
                                            nextTabIndex = tabInfoList[i + deltaSign].Id;
                                        ucTabs.SelectTab(nextTabIndex);
                                        break;
                                    }
                                }
                            }
                        }
                    }));
        }

        private void PreviewMouseHookEvent(object sender, PreviewMouseHookCancelArgs e)
        {
            bool isProcessName = false;
            string processExecutableName = Win32Helper.GetActiveProcessExecutableName(out isProcessName);
            e.ProcessExecutableName = processExecutableName;
            if (!String.IsNullOrEmpty(processExecutableName) && SettingsManager.CurrentSettings.IsProgramExcluded(processExecutableName, !isProcessName))
            {
                e.Cancel = true;
            }
        }

        private void PreviewMouseWheelHookEvent(object sender, PreviewMouseHookCancelArgs e)
        {
            //IsActive is not allowed from this thread. Pass this event in any case to all applications
        }

        #region Commands Execution Methods

        private void AddFile_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            ucLauncher.AddFile();
        }

        private void AddFolder_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            ucLauncher.AddFolder();
        }

        private void AddRunningProgram_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            CreatePopup();
            RunningProgramsUC programs = null;
            if (_popup.placeholder.Child is RunningProgramsUC)
            {
                programs = (RunningProgramsUC)_popup.placeholder.Child;
            }
            else
            {
                programs = new RunningProgramsUC();
                programs.RunningProgramSelected += new LaunchItemSelected(RunningProgramSelected);
                programs.Closed += new EventHandler((o, args) => CancelPopup());
                _popup.placeholder.Child = programs;
            }

            programs.Refresh();
            SetLauncherDisabled(true);
            _popup.IsOpen = true;
        }

        private void AddTab_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            CreatePopup();
            AddEditTabUC ucAddEditTab = null;
            if (_popup.placeholder.Child is AddEditTabUC)
            {
                ucAddEditTab = (AddEditTabUC)_popup.Child;
            }
            else
            {
                ucAddEditTab = new AddEditTabUC();
                _popup.placeholder.Child = ucAddEditTab;
            }

            ucAddEditTab.IsEdit = false;
            ucAddEditTab.tabTitle.Text = String.Empty;
            SetLauncherDisabled(true);
            _popup.IsOpen = true;
        }

        private void AddTab_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            if (ucTabs.tabs.Items.Count < 10)
                e.CanExecute = true;
            else
                e.CanExecute = false;
        }

        private void AddUrlInternal(string url)
        {
            AddWebUrlItem(url, null);
            ucLauncher.Refresh();
        }

        public static void AddWebUrlItem(string url, string title)
        {
            if (String.IsNullOrEmpty(url))
                return;

            url = NormalizeUrl(url);

            UserSettings settings = SettingsManager.CurrentSettings;
            LauncherItem item = new LauncherItem()
            {
                LaunchPath = url,
                ItemNumber = settings.LauncherItems.Count,
                TabId = App.MainWindowInstance.ucTabs.CurrentTab,
                IsUrl = true,
                ToolTip = title
            };

            settings.LauncherItems.Add(item);
            settings.SettingChanged();

            ThreadPool.QueueUserWorkItem(IconHelper.ExtractFavoriteIcon, item);
        }

        public static string NormalizeUrl(string url)
        {
            if (!String.IsNullOrEmpty(url))
            {
                //if no schema defined then add default http
                if ((url.IndexOf(Constants.Http, 0, 7) == -1) && (url.IndexOf(Constants.Https, 0, 8) == -1))
                    url = String.Format(@"{0}{1}", Constants.Http, url);
            }

            return url;
        }

        private void AddUrl_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            CreatePopup();
            if (!(_popup.placeholder.Child is UrlsUC))
            {
                UrlsUC url = new UrlsUC();
                _popup.placeholder.Child = url;
            }

            SetLauncherDisabled(true);
            _popup.IsOpen = true;
        }

        private void Delete_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            LauncherItemUC launcherItem = e.Parameter as LauncherItemUC;
            if (launcherItem != null)
            {
                ucLauncher.DeleteItem(launcherItem.ItemNumber);
            }
        }

        private void Disable_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            Settings.IsDisable = !Settings.IsDisable;
            Settings.SettingChanged();
            SetEnableDisableMenuItem(false);
        }

        private void DontHidePanel_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            Settings.DontHidePanel = tbtnPin.IsChecked.Value;
            Settings.SettingChanged();
        }

        private void Exit_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            Exit(sender, e);
        }

        private void ApplySettings_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            if (_popup != null && _popup.placeholder.Child is SettingsUC)
            {
                SettingsUC settingsUC = (SettingsUC)_popup.placeholder.Child;
                if (!settingsUC.ApplySetting())
                    return;

                ucLauncher.Refresh(true, null); //drop cache on settings change (compact and items per row settings)
                ucTabs.SetControlWidth();
                ucSystemButtonsBar.Width = ucLauncher.CanvasRoot.Width;
                _popup.IsOpen = false;
            }
            SetLauncherDisabled(false);
        }

        private void CancelPopup_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            CancelPopup();
        }

        private void ShowSettings_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            CreatePopup();
            if (!(_popup.placeholder.Child is SettingsUC))
            {
                SettingsUC settings = new SettingsUC();
                _popup.placeholder.Child = settings;
            }

            SetLauncherDisabled(true);
            _popup.IsOpen = true;
        }

        private void EditItem_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            LauncherItemUC launcherItem = e.Parameter as LauncherItemUC;
            CreatePopup();
            if (_popup.placeholder.Child is EditItemUC)
            {
                EditItemUC editControl = null;
                editControl = _popup.placeholder.Child as EditItemUC;
                editControl.SetItem(launcherItem.Item);
                editControl.SetIcon(launcherItem.ItemBitmapSource);
            }
            else
            {
                EditItemUC editControl = null;
                editControl = new EditItemUC(launcherItem.Item);
                _popup.placeholder.Child = editControl;
                editControl.SetIcon(launcherItem.ItemBitmapSource);
            }

            SetLauncherDisabled(true);
            _popup.IsOpen = true;
        }

        private void SaveItemSettings_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            if (_popup != null && _popup.placeholder.Child is EditItemUC)
            {
                EditItemUC ucEditItem = (EditItemUC)_popup.placeholder.Child;
                ucEditItem.ApplySetting();
                ucLauncher.Refresh();
                _popup.IsOpen = false;
            }
            SetLauncherDisabled(false);
        }

        private void SendToAnotherTab_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            TabInfo tabInfo = (TabInfo)((MenuItem)e.Parameter).DataContext;
            int currentItemNumber = tabInfo.ContextMenuOwner.Item.ItemNumber;
            LauncherItem currentItem = SettingsManager.CurrentSettings.LauncherItems.FirstOrDefault(i => i.ItemNumber == currentItemNumber);
            if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
            {
                LauncherItem item = currentItem.Clone();
                item.TabId = tabInfo.Id;
                item.ItemNumber = Settings.LauncherItems.Count;
                Settings.LauncherItems.Add(item);
            }
            else
            {
                currentItem.TabId = tabInfo.Id;
            }
            SettingsManager.CurrentSettings.SettingChanged();
            ucLauncher.Refresh();
        }

        private void EditTab_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            CreatePopup();
            AddEditTabUC ucAddEditTab = null;
            if (_popup.placeholder.Child is AddEditTabUC)
            {
                ucAddEditTab = (AddEditTabUC)_popup.placeholder.Child;
            }
            else
            {
                ucAddEditTab = new AddEditTabUC();
                _popup.placeholder.Child = ucAddEditTab;
            }

            ucAddEditTab.SetItem((int)e.Parameter);
            ucAddEditTab.IsEdit = true;
            SetLauncherDisabled(true);
            _popup.IsOpen = true;
        }

        private void RemoveTab_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            int removeTabId = (int)e.Parameter;
            if (Settings.LauncherItems.Where(i => i.TabId == removeTabId).Count() > 0)
            {
                CreatePopup();
                RemoveTabUC ucRemoveTab = new RemoveTabUC(removeTabId);
                _popup.placeholder.Child = ucRemoveTab;
                SetLauncherDisabled(true);
                _popup.IsOpen = true;
            }
            else
            {
                ucTabs.RemoveTab(removeTabId);
                ucTabs.tabs.Focus();
            }
        }

        private void SaveTabSettings_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            if (_popup != null && _popup.placeholder.Child is AddEditTabUC)
            {
                AddEditTabUC ucAddEditTab = (AddEditTabUC)_popup.placeholder.Child;
                if (ucAddEditTab != null && !String.IsNullOrEmpty(ucAddEditTab.tabTitle.Name))
                {
                    if (ucAddEditTab.IsEdit)
                    {
                        TabInfo currentTabInfo = SettingsManager.CurrentSettings.TabInfoList.FirstOrDefault(i => i.Id == ucAddEditTab.Item.Id);
                        currentTabInfo.Name = ucAddEditTab.tabTitle.Text;
                        SettingsManager.CurrentSettings.SettingChanged();
                    }
                    else
                    {
                        if (Settings.TabInfoList.Count < 10)
                            ucTabs.AddTab(ucAddEditTab.tabTitle.Text);
                    }
                }
            }
            ucTabs.LoadTabs();
            ucLauncher.Refresh(true, null);
            _popup.IsOpen = false;
            SetLauncherDisabled(false);
        }

        private void SaveUrl_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            if (_popup != null && _popup.placeholder.Child is UrlsUC)
            {
                UrlsUC ucUrl = (UrlsUC)_popup.Child;
                ucUrl.AddNewUrl();
                ucLauncher.Refresh();
                _popup.IsOpen = false;
            }
            SetLauncherDisabled(false);
        }

        private void CheckUpdates_Executed(object sender, RoutedEventArgs e)
        {
            UpdateManager.CheckForUpdatesAsync();
        }

        private void SetLanguage_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            CultureInfo culture = (CultureInfo)((MenuItem)sender).CommandParameter;
            ResourceManager.SetCulture(culture);
        }

        private void About_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            CreatePopup();
            if (!(_popup.placeholder.Child is AboutUC))
            {
                AboutUC about = new AboutUC();
                _popup.placeholder.Child = about;
            }

            SetLauncherDisabled(true);
            _popup.IsOpen = true;
        }

        #endregion

        #region Layered Windows Bug Workaround
        /// <summary>
        /// This is a workaround for WPF problem with rendering minimized layered windows after suspend/resume and lock/unlock desktop
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void utility_SessionChanged(object sender, SessionNotificationEventArgs e)
        {
            if (e.Notification == SessionNotification.Unlock)
            {
                ucLauncher.ClearItemsCache(); //bug with windows xp after restore session

                if (IsVisible && Settings.DontHidePanel)
                    return;

                Left = farAwayLeft;
                ShowWindow();
                HideWindow();
            }
        }
        #endregion

        #region Window Events

        private void Window_Activated(object sender, EventArgs e)
        {
            if (!IsStarting.HasValue)
                IsStarting = true;

            if (PopupUC.IsAnyPopupOpen)
                Topmost = false;

            if (ucLauncher.DragIsActive)
                ucLauncher.DragIsActive = false;
        }

        private void Window_Deactivated(object sender, EventArgs e)
        {
            if (!PopupUC.IsAnyPopupOpen)
                HideWindow();
            else
                Topmost = true;
        }

        private void Window_Minimize(object sender, EventArgs e)
        {
            base.Hide();
            Topmost = false;
        }

        private void Window_Initialized(object sender, EventArgs e)
        {

#if SNOOP
            AllowsTransparency = false;
            WindowStyle = WindowStyle.ToolWindow;
            Background = Brushes.Transparent;
            ShowInTaskbar = true;
#endif
            #region Layered Windows Bug Workaround
            _sessionNotificationUtility = new SessionNotificationUtil(this);
            _sessionNotificationUtility.SessionChanged += new EventHandler<SessionNotificationEventArgs>(utility_SessionChanged);
            #endregion
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            AdjustMouseExtender();
            HideWindow();
        }

        private void Window_ContentRendered(object sender, EventArgs e)
        {
            _isContentRendered = true;
            SetCorrectWindowStyle();
            SetEnableDisableMenuItem();
            ShowHideCloseButton();
            tbtnPin.IsChecked = Topmost = Settings.DontHidePanel;
            ucSystemButtonsBar.Width = ucLauncher.CanvasRoot.Width;
            if (!SingleInstanceManager.IsAutoStarted)
                ShowWindow(true);
            //finish window startup initialization
            MemoryHelper.MinimizeWorkingSet(true);
        }

        private void Window_LayoutUpdated(object sender, EventArgs e)
        {
            if (IsStarting.HasValue && IsStarting == true && _isContentRendered == true)
            {
                IsStarting = false;
                Cursor = Cursors.Arrow;
            }
        }

        private void Window_Unloaded(object sender, RoutedEventArgs e)
        {
            if (_sessionNotificationUtility != null)
            {
                _sessionNotificationUtility.Dispose();
            }
        }

        /// <summary>
        /// Workaround for context menu shown on ME activation
        /// </summary>
        private void Window_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (_activationStarted)
            {
                e.Handled = true;
                _activationStarted = false;
            }
        }

        #endregion

        #region Tray icon Menu

        private void MenuItem_ExitClick(object sender, RoutedEventArgs e)
        {
            Exit_Executed(sender, null);
        }

        private void MenuItem_ShowClick(object sender, EventArgs e)
        {
            Point point = tbIcon.PointToScreen(Mouse.GetPosition(tbIcon));
            ShowInPoint(point);
        }

        private void MenuItem_DisableClick(object sender, RoutedEventArgs e)
        {
            Disable_Executed(sender, null);
        }

        private void MenuItem_AboutClick(object sender, RoutedEventArgs e)
        {
            About_Executed(sender, null);
        }

        private void SetLanguage_Click(object sender, RoutedEventArgs e)
        {
            SetLanguage_Executed(sender, null);
        }

        private void MenuItem_ShowSettings(object sender, RoutedEventArgs e)
        {
            if (!this.IsVisible)
                MenuItem_ShowClick(sender, null);
            ShowSettings_Executed(sender, null);
        }

        private void tbIcon_TrayLeftMouseDown(object sender, RoutedEventArgs e)
        {
            if (UpdateManager.UpdatesInfo.Status > UpdateManager.UpdateStatus.NoUpdatesAvailable)
            {
                ShowUpdatesNotification();
            }
            else
            {
                System.Drawing.Point point = System.Windows.Forms.Cursor.Position;
                ShowInPoint(new Point(point.X, point.Y));
            }
        }

        #endregion

        #region Drag & Drop

        private void DragDrop(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                string[] files = e.Data.GetData(DataFormats.FileDrop, true) as string[];

                foreach (string file in files)
                {
                    if (file.EndsWith(".lnk"))
                    {
                        ShellLink shortcut = new ShellLink(file);
                        if (System.IO.File.Exists(shortcut.Target))
                        {
                            ucLauncher.AddFile(shortcut.Target, shortcut.IconPath, shortcut.IconIndex, shortcut.WorkingDirectory, shortcut.Arguments);
                        }
                    }
                    else
                    {
                        if (System.IO.File.Exists(file))
                        {
                            ucLauncher.AddFile(file);
                        }
                        else
                        {
                            if (System.IO.Directory.Exists(file))
                            {
                                ucLauncher.AddFolder(file);
                            }
                        }
                    }
                }
            }
            else
            {
                //if dragging URL or text or smth that can be URL
                if (e.Data.GetDataPresent(DataFormats.Text, true))
                {
                    object possibleUrlObject = e.Data.GetData(DataFormats.Text, true);
                    if (possibleUrlObject != null)
                    {
                        string possibleUrl = possibleUrlObject.ToString();
                        if (Constants.UrlResourceRegex.IsMatch(possibleUrl))
                        {
                            //do something
                            AddUrlInternal(possibleUrl);
                        }
                    }
                }
            }
        }

        #endregion

        private void ucLauncher_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            ucTabs.SetControlWidth();
        }

        private void ucTabs_TabChanged(object sender, TabChangedEventArgs e)
        {
            ucLauncher.Refresh(false, e.ChangeInfo);
        }

        #endregion

        private void ChangeTab_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            if (e.Parameter != null)
            {
                int tabNumber = -1;
                if (Int32.TryParse(e.Parameter.ToString(), out tabNumber))
                {
                    if (IsActive && !ucLauncher.DragIsActive)
                    {
                        List<TabInfo> tabInfoList = SettingsManager.CurrentSettings.TabInfoList;
                        if (tabNumber < tabInfoList.Count)
                        {
                            ucTabs.SelectTab(tabInfoList[tabNumber].Id);
                        }
                    }
                }
            }
        }

    }
}
